# koroFileHeader at Yungoal acer
# Create: 2023-10-19 13:43:26
# LastEdit: 2023-10-26 18:00:44
"""资源管理
https://next.api.aliyun.com/api-tools/sdk/ResourceManager
"""
__author__ = '749B'
# pylint: disable=missing-class-docstring

from django.contrib import admin
from django.db import models
from django.utils.html import format_html_join
from django.utils.safestring import mark_safe


class ResourceGroup(models.Model):
    name = models.CharField(max_length=50, verbose_name="唯一标识")
    rid = models.CharField(max_length=32, unique=True, verbose_name='资源组ID')
    display_name = models.CharField(max_length=50, verbose_name="显示名称")
    STATUS_CHOICES = [
        ('Creating', '创建中'),
        ('OK', '创建成功'),
        ('PendingDelete', '等待删除'),
        ]
    status = models.CharField(max_length=16, choices=STATUS_CHOICES)
    account_id = models.CharField(max_length=32, verbose_name='所属账号ID')
    create_date = models.DateTimeField(verbose_name='创建时间')

    ctime = models.DateTimeField(auto_now_add=True, verbose_name="首次同步时间")
    utime = models.DateTimeField(auto_now=True, verbose_name="最近更新时间")
    dtime = models.DateTimeField(blank=True, null=True, verbose_name="发现删除时间")

    acc = models.ForeignKey('Account', on_delete=models.CASCADE)
    tag_key = models.ManyToManyField('TagKey', through="TagValueRg")

    @admin.display(description='标签')
    def tag_str(self):
        return ', '.join(self.tag_key.values_list('key', flat=True))

    def __str__(self):
        return self.display_name

    class Meta:
        verbose_name = '资源组'
        verbose_name_plural = '资源组列表'
        # 联合唯一约束
        constraints = [
            models.UniqueConstraint(
                fields=['acc', 'name'],
                name='unique_acc_name',
                ),
            ]

class ResourceGroupAdmin(admin.ModelAdmin):
    list_display = [
        'name', 'rid', 'display_name', 
        'status', 'create_date',
        'utime', 'dtime',
        'tag_str',
        ]
    readonly_fields = [
        'ctime', 'utime',
        'tag_key_value',
        ]
    list_filter = ['acc']

    @admin.display(description='标签')
    def tag_key_value(self, obj):
        return format_html_join(
            mark_safe("<br>"),
            "{}={}",
            ((m.tag_key.key, m.value) for m in obj.tagvaluerg_set.all()),
        )


class Resource(models.Model):
    # 资源ID并不一定唯一，已经发现统一账号下会有相同资源ID的两个资源
    # 资源ARN必须唯一，ARN的几个元素组成联合唯一
    rid = models.CharField(max_length=32, verbose_name='资源ID')
    rgid = models.CharField(max_length=32, verbose_name='资源组ID')
    service = models.CharField(max_length=32, verbose_name='云服务')
    resource_type = models.CharField(max_length=32, verbose_name='资源类型')
    region_id = models.CharField(max_length=32, verbose_name='地域')
    create_date = models.DateTimeField(verbose_name='创建时间')

    ctime = models.DateTimeField(auto_now_add=True, verbose_name="首次同步时间")
    utime = models.DateTimeField(auto_now=True, verbose_name="最近更新时间")
    dtime = models.DateTimeField(blank=True, null=True, verbose_name="发现删除时间")

    resource_group = models.ForeignKey('ResourceGroup', on_delete=models.CASCADE)
    tag_key = models.ManyToManyField('TagKey', through="TagValueRes")

    @staticmethod
    def _dict_from_map(data_map: dict):
        _m = data_map.copy()
        data = {
            'rid': _m.pop('ResourceId'),
            'rgid': _m.pop('ResourceGroupId'),
            'service': _m.pop('Service'),
            'resource_type': _m.pop('ResourceType'),
            'region_id': _m.pop('RegionId'),
            'create_date': _m.pop('CreateDate'),
            }
        return data

    # pylint: disable=attribute-defined-outside-init
    @classmethod
    def create_from_map(
        cls, data_map: dict,
        resource_group: ResourceGroup = None,
        resource_group_id: str = None,
        ):
        """使用SDK返回的字典生成实例"""
        data = cls._dict_from_map(data_map)
        obj = cls(**data)
        if resource_group:
            obj.resource_group = resource_group
        elif resource_group_id:
            obj.resource_group_id = resource_group_id
        return obj

    def changed_from_map(
        self,
        sync_time,
        resource_group_id: str = None,
        ):
        """只有所属资源组能转移"""
        self.utime = sync_time
        fields = ['utime']
        if resource_group_id and self.resource_group_id != resource_group_id:
            self.resource_group_id = resource_group_id
            fields.append('resource_group')
        return self, fields

    @property
    def arn(self):
        """资源ARN
        https://help.aliyun.com/zh/resource-management/product-overview/types-of-resources-that-support-tag-api-operations
        资源ARN的格式为arn:acs:${Service}:${Region}:${Account}:${ResourceType}/${ResourceId}
        Service: 云服务code。
        Region: 地域ID。
        Account: 阿里云账号ID。
        ResourceType: 资源类型。
        ResourceId: 资源ID。
        """
        return f'arn:acs:{self.service}:{self.region_id}:'\
            f'{self.resource_group.acc.account_id}:{self.resource_type}/{self.rid}'

    def __str__(self):
        return self.rid

    class Meta:
        verbose_name = '资源信息'
        verbose_name_plural = '资源信息表'
        # 联合唯一约束
        constraints = [
            models.UniqueConstraint(
                fields=['rid', 'rgid', 'service', 'resource_type', 'region_id'],
                name='unique_arn',
                ),
            ]

class ResourceAdmin(admin.ModelAdmin):
    list_display = [
        'rid', 'rgid', 
        'service', 'resource_type', 'region_id',
        'create_date',
        'utime', 'dtime',
        ]
    readonly_fields = [
        'ctime', 'utime',
        'arn',
        ]
